﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;

namespace CPPEI.Net
{
    public class BufferUtil
    {
        /// <summary>
        /// 获取高8位
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public static byte GetHigh(int value)
        {
            return (byte)((value >> 8) & 0xFF);
        }

        /// <summary>
        /// 获取低8位
        /// </summary>
        /// <param name="value"></param>
        /// <returns></returns>
        public static byte GetLow(int value)
        {
            return (byte)(value & 0xFF);
        }

        public static int Combine(byte low, byte high)
        {
            return (high<<8) | low;
        }

        public static void IntToBuffer(int value, byte[] buffer, ref int offset)
        {
            byte[] data = BitConverter.GetBytes(value);
            for (int index = 0; index < data.Length; index++)
            {
                buffer[offset] = data[index];
                offset++;
            }
        }

        public static int IntFromBuffer(byte[] buffer, ref int offset)
        {
            int value  = BitConverter.ToInt32(buffer, offset);
            offset += 4;
            return value;
        }

        #region uint
        /// <summary>
        /// 把uint拷贝到buffer中，uint占4byte，32bit
        /// </summary>
        /// <param name="value"></param>
        /// <param name="buffer"></param>
        /// <param name="offset"></param>
        public static void UIntToBuffer(uint value, byte[] buffer, ref int offset)
        {
            byte[] data = BitConverter.GetBytes(value);
            for (int index = 0; index < data.Length; index++)
            {
                buffer[offset] = data[index];
                offset++;
            }
        }

        /// <summary>
        /// 从buffer中读取一个uint出来，uint占4byte,32bit
        /// </summary>
        /// <param name="buffer"></param>
        /// <param name="offset"></param>
        /// <returns></returns>
        public static uint UIntFromBuffer(byte[] buffer, ref int offset)
        {
            uint value = BitConverter.ToUInt32(buffer, offset);
            offset += 4;
            return value;
        }
        #endregion

        #region ushort
        /// <summary>
        /// 把ushort拷贝到buffer中，ushort占2byte，16bit
        /// </summary>
        /// <param name="value"></param>
        /// <param name="buffer"></param>
        /// <param name="offset"></param>
        public static void UShortToBuffer(ushort value, byte[] buffer, ref int offset)
        {
            buffer[offset] = (byte)(value & 0xFF);
            ushort tempValue = (ushort)(value >> 8);
            buffer[offset + 1] = (byte)(tempValue & 0xFF);
            offset += 2;
        }

        public static ushort UShortFromBuffer(byte[] buffer, ref int offset)
        {
            ushort value = (ushort)buffer[offset];
            value = (ushort)((((ushort)buffer[offset + 1]) << 8) | value);
            offset += 2;
            return value;
        }
        #endregion

        #region byte
        public static void ByteToBuffer(byte value, byte[] buffer, ref int offset)
        {
            buffer[offset] = value;
            offset++;
        }

        public static byte ByteFromBuffer(byte[] buffer, ref int offset)
        {
            byte value = buffer[offset]; 
            offset++;
            return value;
        }
        #endregion

        #region Boolean

        /// <summary>
        /// 
        /// </summary>
        /// <param name="value"></param>
        /// <param name="buffer"></param>
        /// <param name="offset"></param>
        public static void BooleanToBuffer(bool value, byte[] buffer, ref int offset)
        {
            if (value)
            {
                buffer[offset] = 0x01;
                offset++;
            }
            else
            {
                buffer[offset] = 0x00;
                offset++;
            }
        }

        public static bool BooleanFromBuffer(byte[] buffer, ref int offset)
        {
            byte value = buffer[offset];
            offset++;
            if (value == 0x01)
            {
                return true;
            }
            return false;
        }
        #endregion

        /// <summary>
        /// 把字符串填充到buffer中，填充区域是[index, index+length)
        /// </summary>
        /// <param name="value"></param>
        /// <param name="buffer"></param>
        /// <param name="offset"></param>
        /// <param name="length"></param>
        public static void StringToBuffer(string value, byte[] buffer, ref int offset, int length)
        {
            byte[] valueBuffer = Encoding.UTF8.GetBytes(value);
            for (int copyIndex = 0; copyIndex < length; copyIndex++)
            {
                if (copyIndex < valueBuffer.Length)
                {
                    buffer[offset + copyIndex] = valueBuffer[copyIndex];
                }
                else
                {
                    buffer[offset + copyIndex] = 0;
                }
            }
            offset += length;
        }

        //public static void StringToBuffer(string value, byte[] buffer, int index, int length, out int newIndex)
        //{
        //    StringToBuffer(value, buffer, index, length);
        //    newIndex = index + length;
        //}

        /// <summary>
        /// 将buffer中的[index, index+length)区域的数据转换为字符串
        /// </summary>
        /// <param name="buffer"></param>
        /// <param name="offset"></param>
        /// <param name="length"></param>
        /// <returns></returns>
        public static string StringFromBuffer(byte[] buffer, ref int offset, int length)
        {
            int offsetTemp = offset;
            offset += length;
            return Encoding.UTF8.GetString(buffer, offsetTemp, length).TrimEnd('\0');
        }

        public static string StringFromBuffer(byte[] buffer, ref int offset)
        {
            int offsetTemp = offset;
            int length = buffer.Length - offsetTemp;
            offset += length;
            return Encoding.UTF8.GetString(buffer, offsetTemp, length).TrimEnd('\0');
        }

        #region double
        public static void DoubleToBuffer(double value, byte[] buffer, ref int offset)
        {
            byte[] data = BitConverter.GetBytes(value);
            for (int index = 0; index < data.Length; index++)
            {
                buffer[offset] = data[index];
                offset++;
            }
        }

        public static double DoubleFromBuffer(byte[] buffer, ref int offset)
        {
            double value = BitConverter.ToDouble(buffer, offset);
            offset += 8;
            return value;
        }

        #endregion


        /// <summary>
        /// 
        /// 如果obj继承IPackage那么就调用IPackage的ToData
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static byte[] ToData(object obj)
        {
            if (obj is IPackage)
            {
                return (obj as IPackage).ToData();
            }
            DataDescription dataDescription = DataDescriptionCache.Instance.GetDescription(obj.GetType());

            byte[] buffer = new byte[dataDescription.Size];
            int offset = 0;
            foreach (FieldDescription field in dataDescription.Fields)
            {
                field.ToBuffer(obj, buffer, ref offset);
            }

            return buffer;
        }

        /// <summary>
        /// 如果T继承IPackage那么就调用IPackage的FromData
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="buffer"></param>
        /// <returns></returns>
        public static T FromData<T>(byte[] buffer)
        {
            T obj = (T)(typeof(T).Assembly.CreateInstance(typeof(T).FullName));
            if (obj is IPackage)
            {
                (obj as IPackage).FromData(buffer);
                return obj;
            }

            DataDescription dataDescription = DataDescriptionCache.Instance.GetDescription(typeof(T));

            int offset = 0;
            foreach (FieldDescription field in dataDescription.Fields)
            {
                field.FromBuffer(obj, buffer, ref offset);
            }

            return obj;
        }

        #region buffer
        public static byte[] BufferFromBuffer(byte[] buffer, ref int offset, int Length)
        {
            byte[] value = new byte[Length];
            System.Buffer.BlockCopy(buffer, offset, value, 0, Length);
            offset += Length;
            return value;
        }

        public static void BufferToBuffer(byte[] value, byte[] buffer, ref int offset, int length)
        {
            if (length > value.Length)
            {
                System.Buffer.BlockCopy(value, 0, buffer, offset, value.Length);
            }
            else
            {
                System.Buffer.BlockCopy(value, 0, buffer, offset, length);
            }
            offset += length;
        }
        #endregion
    }
}
